﻿using UnityEngine;
using System.Collections.Generic;

public class CityManager : MonoBehaviour {

    public City city;

    // Used to access the LogicalBoard that's receiving signals.
    public LogicalBoardManager logicalBoardManager;

    public bool useMockBoard = false;

    public int forceCityWidth = 12;
    public int forceCityHeight = 8;

    public GameObject gridSpace = null;

    private GameObject[] gridSpaces;

    public GameObject[] buildings;
    private Dictionary<string, Building> buildingsByName = new Dictionary<string, Building>();
    private Dictionary<Building.BuildingType, GameObject> buildingsByType = new Dictionary<Building.BuildingType, GameObject>();
    private Dictionary<int, GameObject> buildingGameObjectsById = new Dictionary<int, GameObject>();

    public float currentScore = 0;

    public Dictionary<string, Building> GetBuildings()
    {
        return buildingsByName;
    }

    // Use this for initialization
	void Start () {

        buildingsByName.Add("None", new Building(Building.BuildingType.Empty, Building.Orientation.East));
        buildingsByType.Add(Building.BuildingType.Empty, null);
        foreach (GameObject building in buildings)
        {
            BuildingData buildingData = building.GetComponent<BuildingData>();

            Building eastBuilding = new Building(buildingData.buildingType, Building.Orientation.East);
            buildingsByName.Add(buildingData.buildingName, eastBuilding);

            if (eastBuilding.size != Building.BuildingSize.Size1x1)
            {
                Building westBuilding = new Building(buildingData.buildingType, Building.Orientation.West);
                Building northBuilding = new Building(buildingData.buildingType, Building.Orientation.North);
                Building southBuilding = new Building(buildingData.buildingType, Building.Orientation.South);

                buildingsByName.Add(buildingData.buildingName + " (West)", westBuilding);
                buildingsByName.Add(buildingData.buildingName + " (North)", northBuilding);
                buildingsByName.Add(buildingData.buildingName + " (South)", southBuilding);
            
            }

            print("trying to add type " + buildingData.buildingType + " to buildingsByType");
            buildingsByType.Add(buildingData.buildingType, building);
        }

        if (logicalBoardManager == null || useMockBoard)
        {
            city = new City(forceCityWidth, forceCityHeight);
        }
        else
        {
            city = logicalBoardManager.GetCity();
        }

        //GameNetworkManager gameRPC = GameObject.FindGameObjectWithTag("GameNetworkManager").GetComponent<GameNetworkManager>();
        //gameRPC.city = city;
        //gameRPC.cityManager = this;


        gridSpaces = new GameObject[city.width * city.height];

        for (int x = 0; x < city.width; x++)
        {
            for (int y = 0; y < city.height; y++)
            {
                GameObject newGridSpace = GameObject.Instantiate(gridSpace, new Vector3(x * -1.25f, 0, y * -1.25f), Quaternion.identity) as GameObject;
                newGridSpace.name = string.Format("{0}-{1}", x, y);
            }
        }
	}

    // Update is called once per frame
    void Update()
    {
        List<BuildingEvent> events = city.FlushBuildingEvents();
        currentScore = city.Score;
        foreach (BuildingEvent buildingEvent in events)
        {
            switch (buildingEvent.type)
            {
                case BuildingEvent.BuildingEventType.Create:
                    print("Create event captured at " + buildingEvent.locations[0]);

                    // TODO: Instantiate with orientation
                    Quaternion orientation = Quaternion.identity;
                    switch (buildingEvent.building.orientation)
                    {
                        case Building.Orientation.North:
                            orientation = Quaternion.AngleAxis(270, Vector3.up);
                            break;
                        case Building.Orientation.South:
                            orientation = Quaternion.AngleAxis(90, Vector3.up);
                            break;
                        case Building.Orientation.West:
                            orientation = Quaternion.AngleAxis(180, Vector3.up);
                            break;
                    }

                    GameObject newBuilding = Network.Instantiate(buildingsByType[buildingEvent.building.type], new Vector3(buildingEvent.locations[0].x * -1.25f, 0.55f, buildingEvent.locations[0].y * -1.25f), orientation, 0) as GameObject;
                    buildingGameObjectsById.Add(buildingEvent.building.GetId(), newBuilding);
                    
                    break;
                case BuildingEvent.BuildingEventType.Destroy:

                    print("Destroy event captured at " + buildingEvent.locations);
                    if (buildingGameObjectsById.ContainsKey(buildingEvent.building.GetId()))
                    {
                        print("Object found to destroy");
                        GameObject buildingGameObjectToDestroy = buildingGameObjectsById[buildingEvent.building.GetId()];
                        Network.RemoveRPCs(buildingGameObjectToDestroy.networkView.viewID);
                        Network.Destroy(buildingGameObjectToDestroy);
                    }

                    break;
            }
        }

	}

    public void DestroyBuilding(int x, int y)
    {
        city.DestroyBuilding(x, y);
    }

    public void ReplaceBuilding(int x, int y, Building building)
    {
        if (city.GetBuilding(x, y) != null)
        {
            print("there is a building at " + x + ", " + y);
            city.DestroyBuilding(x, y);
        }
        else
        {
            print("no building found at " + x + ", " + y);
        }

        city.AddBuilding(x, y, building);
    }

    void OnGUI()
    {
        if (GUILayout.Button("Get Recommendation"))
        {
            print(city.GetRecommendationCode());
        }
        GUI.Label(new Rect(10, 50, 50, 20), currentScore.ToString(), new GUIStyle() { fontSize = 20 });
    }


    internal bool ValidatePlacementAvailable(int x, int y)
    {
        if (x < 0 || x > city.width - 1) return false;
        if (y < 0 || y > city.height - 1) return false;

        Vector2 position = new Vector2(x, y);

        if (city.BuildingsByTile.ContainsKey(position))
        {
            return false;
        }

        return true;
    }
}
